package org.example.completableFuture;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;

/**
 * @Classname Test
 * @Description TODO
 * @Date 2021/4/7 11:03 上午
 * @Created by xiangjd
 */
public class Test {

    private static final ExecutorService executor = Executors.newSingleThreadExecutor();

    public static void main(String[] args) {

        CompletableFuture<Void> rFuture = CompletableFuture
                .runAsync(() -> System.out.println("hello siting"), executor);
        //supplyAsync的使用
        CompletableFuture<String> future = CompletableFuture
                .supplyAsync(() -> {
                    System.out.print("hello ");
                    return "siting";
                }, executor);

        //阻塞等待，runAsync 的future 无返回值，输出null
        System.out.println(rFuture.join());
        //阻塞等待
        String name = future.join();
        System.out.println(name);
        executor.shutdown(); // 线程池需要关闭
//        --------输出结果--------
//        hello siting
//        null
//        hello siting

    }

    ////////////////////////////////////串行执行串行执行////////////////////////////////////

    /**
     * 任务完成则运行action，不关心上一个任务的结果，无返回值
     */
    @org.junit.Test
    public void test1() {
        CompletableFuture<Void> future = CompletableFuture
                .supplyAsync(() -> "hello siting", executor)
                .thenRunAsync(() -> System.out.println("OK"), executor);
        executor.shutdown();
//        --------输出结果--------
//        OK

    }

    /**
     * 任务完成则运行action，依赖上一个任务的结果，无返回值
     */
    @org.junit.Test
    public void test2() {
        CompletableFuture<Void> future = CompletableFuture
                .supplyAsync(() -> "hello siting", executor)
                .thenAcceptAsync(System.out::println, executor);
        executor.shutdown();
//        --------输出结果--------
//        hello siting
    }

    /**
     * 任务完成则运行fn，依赖上一个任务的结果，有返回值
     */
    @org.junit.Test
    public void test3() {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        CompletableFuture<String> future = CompletableFuture
                .supplyAsync(() -> "hello world", executor)
                .thenApplyAsync(data -> {
                    System.out.println(data);
                    return "OK";
                }, executor);
        System.out.println(future.join());
        executor.shutdown();
//        --------输出结果--------
//        hello world
//        OK
    }


    /**
     * thenCompose - 任务完成则运行fn，依赖上一个任务的结果，有返回值
     */
    @org.junit.Test
    public void test4() {
        //第一个异步任务，常量任务
        CompletableFuture<String> f = CompletableFuture.completedFuture("OK");
        //第二个异步任务
        ExecutorService executor = Executors.newSingleThreadExecutor();
        CompletableFuture<String> future = CompletableFuture
                .supplyAsync(() -> "hello world", executor)
                .thenComposeAsync(data -> {
                    System.out.println(data);
                    return f; //使用第一个任务作为返回
                }, executor);
        System.out.println(future.join());
        executor.shutdown();
//        --------输出结果--------
//        hello world
//        OK
    }

    ////////////////////////////////////并行执行并行执行////////////////////////////////////


    /**
     * 两个CompletableFuture[并行]执行完，然后执行action，不依赖上两个任务的结果，无返回值
     */
    @org.junit.Test
    public void test5(){
//第一个异步任务，常量任务
        CompletableFuture<String> first = CompletableFuture.completedFuture("hello world");
        ExecutorService executor = Executors.newSingleThreadExecutor();
        CompletableFuture<Void> future = CompletableFuture
                //第二个异步任务
                .supplyAsync(() -> "hello siting", executor)
                // () -> System.out.println("OK") 是第三个任务
                .runAfterBothAsync(first, () -> System.out.println("OK"), executor);
        executor.shutdown();
//        --------输出结果--------
//        OK

    }


    /**
     * 两个CompletableFuture[并行]执行完，然后执行action，依赖上两个任务的结果，无返回值
     */
    @org.junit.Test
    public void test6(){
//第一个异步任务，常量任务
        CompletableFuture<String> first = CompletableFuture.completedFuture("hello world");
        ExecutorService executor = Executors.newSingleThreadExecutor();
        CompletableFuture<Void> future = CompletableFuture
                //第二个异步任务
                .supplyAsync(() -> "hello siting", executor)
                // (w, s) -> System.out.println(s) 是第三个任务
                .thenAcceptBothAsync(first, (s, w) -> System.out.println(s), executor);
        executor.shutdown();
//        --------输出结果--------
//        hello siting

    }


    //........


    @org.junit.Test
    public void test7()throws InterruptedException, ExecutionException {
        // 不存在并发插入情况，不需要使用ConcurrentHashMap
//		Map<String, String> data = new ConcurrentHashMap<>(3);
        Map<String, String> data = new HashMap<>(3);
        //第一个任务。
        CompletableFuture<String> task01 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task01";
        });
        //第二个任务。
        CompletableFuture<String> task02 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task02";
        });
        // 第三个任务
        CompletableFuture<String> task03 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task03";
        });
        // get()方法会阻塞
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS");
        data.put("task01", task01.get());
        System.out.printf("task01执行完毕;当前时间:%s\n", formatter.format(LocalDateTime.now()));
        data.put("task02", task02.get());
        System.out.printf("task02执行完毕;当前时间:%s\n", formatter.format(LocalDateTime.now()));
        data.put("task03", task03.get());
        System.out.printf("task03执行完毕;当前时间:%s\n", formatter.format(LocalDateTime.now()));
        System.out.println(data);


    }

}
